using System;
using System.Data;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

/*
Keyboard

*/
namespace DbView
{
	/// <summary>
	/// Summary description for ViewEditForm.
	/// </summary>
	public partial class ViewEditForm : System.Windows.Forms.Form
	{
		/*
				private Model this.m_Model;
				private ViewParams this.m_vp;
				private DateFormatManager this.m_DateFormatManager;
		*/
		public ViewEditForm(ViewDefinition viewDef, Model model)
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

			this.m_ViewDef = viewDef;
			this.m_OriginalName = viewDef.Name; // hold original view name for duplicate name detection.
			this.m_Model = model;
			//
			GetSchemaInfo();
			ControlsfromViewParams();
			// initial setting
			btnClone.Enabled = (this.m_ViewDef.IsPermanent);
			// Configure drag and drop
			this.m_DragManager = new DragDropManager(false); // w.o mouse for the moment.
			this.m_DragManager.ConfigureDragDrop(this.listFields, this.listViewFields, DragDropEffects.Copy);
			this.m_DragManager.EnableDragDropMove(this.listViewFields, false);
			this.m_DragManager.ConfigureDragDrop(this.listViewFields, this.listSortFields, DragDropEffects.Copy);
			this.m_DragManager.ConfigureDragDrop(this.listViewFields, this.listFilterFields, DragDropEffects.Copy);
			this.m_DragManager.ConfigureDragDrop(this.listViewFields, this.listNumsearchFields, DragDropEffects.Copy);
			// attach navigators
			this.listFields.Tag = new ListNavigator(listFields, listNumsearchFields, listViewFields);
			this.listViewFields.Tag = new ListNavigator(listViewFields, listFields, listSortFields);
			this.listSortFields.Tag = new ListNavigator(listSortFields, listViewFields, listFilterFields);
			this.listFilterFields.Tag = new ListNavigator(listFilterFields, listSortFields, listNumsearchFields);
			this.listNumsearchFields.Tag = new ListNavigator(listNumsearchFields, listFilterFields, listFields);

			// help
			ToolTip toolTipHelp = new ToolTip();

			// Set up the delays for the ToolTip.
			toolTipHelp.AutoPopDelay = 20000;
			toolTipHelp.InitialDelay = 250;
			toolTipHelp.ReshowDelay = 100;
			toolTipHelp.ShowAlways = true;
			// Force the ToolTip text to be displayed whether or not the form is active.
			ConfigureToolTipHelp(toolTipHelp, HELP_STRING);
			// tie to the check box
			chkHelpTips.Tag = toolTipHelp;
			SynchronizeToolTipState(chkHelpTips);
			// check and hide if necessary the lookup option
			CheckHideLookupButton();
		}


		/*
			Expecting a string of form
			Control Name
			Help
			[More help]
			%%%
		*/
		void ConfigureToolTipHelp(ToolTip toolTipHelp, string helpString)
		{
			String[] helpLines = helpString.Split('\n');
			int state = 0;
			string controlName = "";
			string controlHelp = "";
			foreach (String helpLine in helpLines)
			{
				string line = helpLine.Trim();
				switch (state)
				{
					case 0:
						if (line.Length > 0)
						{
							controlName = line;
							state = 1;
						}
						break;
					case 1:
						if (line == "%%%")
						{
							Control c = this.Controls[controlName];
							toolTipHelp.SetToolTip(c, controlHelp);
							controlHelp = "";
							state = 0;
						}
						else
						{
							if (controlHelp.Length > 0) controlHelp += "\n";
							controlHelp += line;
						}
						break;
				}
			}
			// set 
			if (this.m_ViewDef.TableName.IndexOf("(") != -1)
			{
				toolTipHelp.SetToolTip(textDescription, textDescription.Text);
				btnShowView.Visible = true;
			}
		}

		private void CheckHideLookupButton()
		{
			bool hideIt = true;
			Object o = this.m_Model.DataSource.TryToGetOptionalInterface(DbViewDriver.OptionalInterface.Lookup);
			if (o != null)
			{
				DbViewDriver.ILookup iface = o as DbViewDriver.ILookup;
				if (iface != null)
					hideIt = false; 
			}
			this.btnLookup.Visible = !hideIt;
		}

		// subtle property - maximimum report columns to 
		public int NewViewMaxColumnCount
		{
			get { return this.m_NewViewMaxColumnCount; }
			set { this.m_NewViewMaxColumnCount = value; }
		}

		public void GotoFilterBox()
		{
			this.ActiveControl = this.textMoreSql;
		}

		private void GetSchemaInfo()
		{
		}

		private void InsertInPlace(String ColumnName, ListBox lb)
		{
			if (lb.Items.IndexOf(ColumnName) < 0)
			{
				lb.Items.Add(ColumnName);
				lb.SelectedIndex = lb.Items.Count - 1;
			}
		}

		private void ListBoxAddFields(ListBox Source, ListBox Dest)
		{
			// clear selection?
			int held_selection = Dest.SelectedIndex;
			Dest.SelectionMode = SelectionMode.One;
			Dest.SelectedIndex = -1;
			// get selected of source
			foreach (int iSelectedIndex in Source.SelectedIndices)
			{
				// get selected string
				string ColumnName = Source.Items[iSelectedIndex].ToString();
				// insert in the right place in dest
				InsertInPlace(ColumnName, Dest);
			}
			Dest.SelectionMode = SelectionMode.MultiExtended;
			// case where nothing was added. The selectio would disappear otherwise
			if (Dest.SelectedIndex == -1)
				Dest.SelectedIndex = held_selection;
		}

		private void ListBoxAddField(ListBox Source, ListBox Dest)
		{
			// get selected of source
			int iSelectedIndex = Source.SelectedIndex;
			// no action if none selected
			if (iSelectedIndex == -1)
				return;
			ListBoxAddFields(Source, Dest);
		}

		private void ListBoxDelField(ListBox lb)
		{
			// get choice for deletion
			int iSelectedIndex = lb.SelectedIndex;
			// no action if button pressed but none selected
			if (iSelectedIndex == -1)
				return;
			// remove the item
			lb.Items.RemoveAt(iSelectedIndex);
			// reset the selection moving up if last item was removed.
			lb.SelectedIndex = (iSelectedIndex < lb.Items.Count) ? iSelectedIndex : iSelectedIndex - 1;
		}

		private void ListBoxDelFields(ListBox lb)
		{
			// get choice for deletion
			int iSelectedIndex = lb.SelectedIndex;
			for (int iIndex = lb.SelectedIndices.Count; iIndex > 0; --iIndex)
			{
				// remove the item
				lb.Items.RemoveAt(lb.SelectedIndices[iIndex - 1]);
			}
			// reset the selection moving up if last item was removed.
			lb.SelectedIndex = (iSelectedIndex < lb.Items.Count) ? iSelectedIndex : iSelectedIndex - 1;
		}

		// deal with noise chars
		static private string makeSearchText(String source)
		{
			return source.Replace("_", "").Replace("-", "").Replace(" ", "").ToUpper();
		}

		private bool Matches(String target, string pattern)
		{
			if (pattern.Length == 0) // no search set
				return true;
			// simple contains
			if (makeSearchText(target).IndexOf(pattern) >= 0)
				return true;
			return false;
		}

		private void PopulateFields(String strMatch)
		{
			listFields.Items.Clear();
			if (strMatch.Length > 0)
				listFields.ForeColor = System.Drawing.Color.Red;
			else
				listFields.ForeColor = System.Drawing.SystemColors.WindowText;

			SchemaField[] Schema = FieldListDef.SchemaFields;
			int iLastCol = Schema.GetLength(0);
			for (int iRowIndex = 0; iRowIndex < iLastCol; ++iRowIndex)
			{
				string fieldName = Schema[iRowIndex].Name;
				if (Matches(fieldName, strMatch))
					listFields.Items.Add(fieldName);
			}
			if (listFields.Items.Count > 0)
				listFields.SelectedIndex = 0;

			SetUpdateButtonState(strMatch.Length == 0);
		}

		private void SetUpdateButtonState(bool isFull)
		{
			// prevent buttons being used for the wrong purpose
			this.btnUpdate.Enabled = isFull;
			this.btnShowAll.Enabled = !isFull;
			// switch on off cancel so that Escape restores to full field list
			this.CancelButton = (isFull) ? this.btnCancel : null;
		}

		private void setMatchString(String NewMatch)
		{
			if (NewMatch.CompareTo(this.m_MatchString) == 0)
				return; // do nothing if nothing to do.
			this.m_MatchString = makeSearchText(NewMatch);
			PopulateFields(this.m_MatchString);
		}

		private void ControlsfromViewParams()
		{
			this.textViewName.Text = this.m_ViewDef.Name;
			//
			this.textDescription.Text = this.m_ViewDef.TableName;
			this.textMoreSql.Text = this.m_ViewDef.ExtraClause;
			this.chkPermanent.Checked = this.m_ViewDef.IsPermanent;

			PopulateFields("");
			int iLastCol = FieldListDef.SchemaFields.GetLength(0);
			if (true)
			{
				// get display fields
				SchemaField[] cols = this.m_ViewDef.DisplayFields;
				// if none defined
				if (cols.Length == 0)
				{
					// use schema fields
					SchemaField[] Schema = FieldListDef.SchemaFields;
					// adjust for a random maximum to start with
					iLastCol = (iLastCol > NewViewMaxColumnCount) ? NewViewMaxColumnCount : iLastCol;
					for (int iRowIndex = 0; iRowIndex < iLastCol; ++iRowIndex)
					{
						string fieldName = Schema[iRowIndex].Name;
						this.listViewFields.Items.Add(fieldName);
					}
				}
				else
				{
					for (int iRowIndex = 0; iRowIndex < cols.GetLength(0); ++iRowIndex)
					{
						string fieldName = cols[iRowIndex].Name;
						this.listViewFields.Items.Add(fieldName);
					}
				}

				SchemaField[] FilterCols = this.m_ViewDef.SearchFields;
				foreach (SchemaField s in FilterCols)
				{
					if (DbView.SchemaField.IsIntegerType(s.Type))
						this.listNumsearchFields.Items.Add(s.Name);
					else
						this.listFilterFields.Items.Add(s.Name);
				}
				SchemaField[] SortCols = this.m_ViewDef.SortFields;
				foreach (SchemaField s in SortCols)
				{
					string orderIndicator = (s.Ord == "D") ? "-" : "+";
					this.listSortFields.Items.Add(orderIndicator + s.Name);
				}
				/*
								string [] NumSearchCols = this.m_ViewDef.NumberSearchColNames;
								foreach (String s in NumSearchCols)
									this.listNumsearchFields.Items.Add(s);
				*/
			}
		}

		private void ViewParamsfromControls()
		{
			ViewDefinition newViewDef = ViewDefinitionManager.makeNewViewDefinition();
			bool makePermanent = this.chkPermanent.Checked;
			newViewDef.SetPermanent(makePermanent);
			newViewDef.Name = textViewName.Text;
			// TODO: Modify here to replace any updated fields
			SchemaField[] Schema = FieldListDef.SchemaFields;
			foreach (SchemaField s in Schema)
				newViewDef.AddField(s);
			// below was reset here, but not for multi-table view
			// this.m_ViewDef.Table = textDescription.Text;

			// get extra sql and strip the where part if necessary
			string strClause = textMoreSql.Text;
			if (strClause.IndexOf("WHERE") == 0 ||
				strClause.IndexOf("where") == 0)
				strClause = strClause.Substring(5 + 1);
			// this.m_ViewDef.ExtraClause = strClause.Trim();
			newViewDef.ExtraClause = strClause.Trim();

			int idx;
			ListBox lb = listSortFields;
			for (idx = 0; idx < lb.Items.Count; ++idx)
			{
				// check from 
				string s = lb.Items[idx].ToString();
				bool bDesc = s[0] == '-' ? true : false;
				if (s[0] == '+' || s[0] == '-') s = s.Substring(1); // trim leading
				SchemaField field = FieldListDef[s];
				if (bDesc)
					field.Ord = "D";
				newViewDef.AddSort(field, bDesc);
			}

			string removed = "";
			lb = listFilterFields;
			for (idx = 0; idx < lb.Items.Count; ++idx)
			{
				string s = lb.Items[idx].ToString();
				SchemaField field = FieldListDef[s];
				if (DbView.SchemaField.IsIntegerType(field.Type) || field.Type == "S")
					newViewDef.AddSearch(field);
				else
					removed += "\n" + field.Name;
			}

			lb = this.listNumsearchFields;
			for (idx = 0; idx < lb.Items.Count; ++idx)
			{
				string s = lb.Items[idx].ToString();
				SchemaField field = FieldListDef[s];
				newViewDef.AddSearch(field);
			}

			lb = listViewFields;
			for (idx = 0; idx < lb.Items.Count; ++idx)
			{
				string s = lb.Items[idx].ToString();
				SchemaField field = FieldListDef[s];
				// gotta convert to number
				newViewDef.AddToDisplay(field);
			}

			if (removed.Length > 0)
				MessageBox.Show("Field not added to filter due to unsuitable type" + removed, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Information);

			// use the clone button colour as a proxy for a proper clone activated flag.
			bool cloning = (this.btnClone.BackColor == System.Drawing.Color.MistyRose);
			
			if (cloning) 
			{
				ViewDefinition originalViewDef = ViewDefinitionManager.makeNewViewDefinition();
				originalViewDef.Copy(this.m_ViewDef);
				originalViewDef.TableName = this.m_ViewDef.TableName;  // very dodgy
				// this to update ie create the clone
				this.m_ViewDef.Copy(newViewDef);
				// now save 
				ViewDefinitionManager.AddOrReplace(originalViewDef, this.m_Model.CurrentConnection);
			}
			else
			{
				this.m_ViewDef.Copy(newViewDef);
			}
			// new view may be broken somehow. Set this flag so it can be identified and destroyed if necessary
			this.m_ViewDef.SetTested(false);
		}

		private bool DuplicateDetected(string newViewName)
		{
			bool isDuplicateDetected = (ViewDefinitionManager.FindView(newViewName, this.m_Model.CurrentConnection) != null);
			
			if (isDuplicateDetected)
			{
				string message = string.Format("{0} is already used for a view name. Please select another", newViewName);
				MessageBox.Show(message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
			}
			return isDuplicateDetected;
		}

		private void CheckClearFilter(ListBox lb)
		{
			for (int idx = lb.Items.Count - 1; idx >= 0; --idx)
			{
				string s = lb.Items[idx].ToString();
				int iPos = listViewFields.Items.IndexOf(s);
				if (iPos == -1)
					lb.Items.RemoveAt(idx);
			}
		}

		private void CheckClearFilters()
		{
			// on delete remove from filters any fields not in the main list
			CheckClearFilter(listFilterFields);
			CheckClearFilter(listNumsearchFields);
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				if (components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose(disposing);
		}
		private void ViewEditForm_Load(object sender, System.EventArgs e)
		{
			this.listFields.Focus();
		}
		private void ViewEditForm_Shown(object sender, EventArgs e)
		{
			this.listFields.Focus();
		}

		private void textViewName_TextChanged(object sender, EventArgs e)
		{
			if (textViewName.Text != this.m_ViewDef.TableName)
				this.chkPermanent.Checked = true;
		}

		private void label2_Click(object sender, System.EventArgs e)
		{

		}

		private void label4_Click(object sender, System.EventArgs e)
		{

		}

		private bool IsSelectedOneATextField()
		{
			// get selected 
			int iSelectedIndex = this.listViewFields.SelectedIndex;
			if (iSelectedIndex == -1)
				return false;
			string ColumnName = (String)this.listViewFields.Items[this.listViewFields.SelectedIndex];

			iSelectedIndex = this.listFields.Items.IndexOf(ColumnName);
			if (iSelectedIndex == -1)
				return false;

			if (FieldListDef[ColumnName].Type == "S")
				return true;
			return false;
		}

		private bool IsSelectedOneANumberField()
		{
			// get selected 
			int iSelectedIndex = this.listViewFields.SelectedIndex;
			if (iSelectedIndex == -1)
				return false;
			string ColumnName = (String)this.listViewFields.Items[this.listViewFields.SelectedIndex];

			iSelectedIndex = this.listFields.Items.IndexOf(ColumnName);
			if (iSelectedIndex == -1)
				return false;

			if (FieldListDef[ColumnName].Type == "I")
				return true;
			return false;
		}

		private bool IsSelectedOneADateField()
		{
			// get selected 
			int iSelectedIndex = this.listViewFields.SelectedIndex;
			if (iSelectedIndex == -1)
				return false;
			string ColumnName = (String)this.listViewFields.Items[this.listViewFields.SelectedIndex];
			iSelectedIndex = this.listFields.Items.IndexOf(ColumnName);
			if (iSelectedIndex == -1)
				return false;
			if (FieldListDef[ColumnName].Type == "D")
				return true;
			return false;
		}

		private string GetSelectedOne()
		{
			// get selected 
			int iSelectedIndex = this.listViewFields.SelectedIndex;
			if (iSelectedIndex == -1)
				return "";
			return (String)this.listViewFields.Items[this.listViewFields.SelectedIndex];
		}

		private void btnCancel_Click(object sender, System.EventArgs e)
		{
			this.DialogResult = DialogResult.Cancel;
			this.Close();
		}

		private void btnSave_Click(object sender, System.EventArgs e)
		{
			if (this.listFields.Focused)
			{
				btnAddField_Click(sender, e);
			}
			else
			{
				// check for name
				// only check when the name has been changed from it's original.
				if (this.m_OriginalName != this.textViewName.Text)
				{
					// call bellow shows an appropriate message and returns true if the new name exists
					if (DuplicateDetected(this.textViewName.Text))
					{
						// so abort save and return to the name field.
						this.textViewName.Focus();
						return;
					}
				}
				// check for date and varbinary fields here
				ViewParamsfromControls();
				this.DialogResult = DialogResult.OK;
				this.Close();
			}
		}
		
		private void btnClone_Click(object sender, EventArgs e)
		{
			// no going back
			this.btnClone.Enabled = false;
			// queue the user to a clone operation
			// the property change will also signal to the save option that cloning is in force
			this.btnClone.BackColor = System.Drawing.Color.MistyRose; 
			// adjust the current name
			this.textViewName.Text += "-Clone";
			// and move to the box to encourage the name to be edited to something more meaningful
			this.textViewName.Select(this.textViewName.Text.Length,0);
			this.textViewName.Focus();
		}

		private void btnAddField_Click(object sender, System.EventArgs e)
		{
			//this.ListBoxAddField(listFields, listViewFields);
			this.ListBoxAddFields(listFields, listViewFields);
			setMatchString("");
		}
		private void listFields_DoubleClick(object sender, System.EventArgs e)
		{
			this.ListBoxAddField(listFields, listViewFields);
			setMatchString("");
		}

		private void btnDelField_Click(object sender, System.EventArgs e)
		{
			DeleteViewField();
		}

		private void btnDelFields_Click(object sender, EventArgs e)
		{
			DeleteViewFieldsFromSelected();
		}

		private void DeleteViewField()
		{
			this.ListBoxDelFields(listViewFields);
			// remove from filters
			CheckClearFilters();
		}

		private void DeleteViewFieldsFromSelected()
		{
			ListBox lb = (ListBox)listViewFields;
			// delete all fields after the cursor
			// get last field to keep for deletion
			int iSelectedIndex = lb.SelectedIndex;
			// Re-enable below to keep the marked field. I prefer otherwise
			++iSelectedIndex;
			while (iSelectedIndex < lb.Items.Count)
				lb.Items.RemoveAt(iSelectedIndex);
			// selection should stay in place                
			// remove from filters
			CheckClearFilters();
		}

		private void listViewFields_DoubleClick(object sender, System.EventArgs e)
		{
			this.ListBoxDelField(listViewFields);
			// remove from filters
			CheckClearFilters();
		}

		private void btnAddFilter_Click(object sender, System.EventArgs e)
		{
			// need to check that it is a text field
			/*
						if (IsSelectedOneATextField())
							this.ListBoxAddField(listFields, listFilterFields);
			*/
			if (IsSelectedOneATextField())
				this.ListBoxAddField(this.listViewFields, listFilterFields);

		}

		private void btnDelFilter_Click(object sender, System.EventArgs e)
		{
			this.ListBoxDelField(listFilterFields);
		}
		private void listFilterFields_DoubleClick(object sender, System.EventArgs e)
		{
			this.ListBoxDelField(listFilterFields);
		}

		private void btnShowView_Click(object sender, EventArgs e)
		{
			SourceForm2 dlg = new SourceForm2(textViewName.Text, textDescription.Text, "");
			dlg.ShowDialog(this);
		}

		private void AddSortField(bool bDesc)
		{
			// get selected of source
			int iSelectedIndex = this.listViewFields.SelectedIndex;
			// no action if none selected
			if (iSelectedIndex == -1)
				return;
			// get selected string
			string ColumnName = listViewFields.Items[iSelectedIndex].ToString();
			string DecoratedColumnName = (bDesc) ? "-" : "+";
			DecoratedColumnName += ColumnName;
			if (listSortFields.Items.IndexOf(DecoratedColumnName) < 0)
				listSortFields.Items.Add(DecoratedColumnName);
		}

		private void btnAddSortAsc_Click(object sender, System.EventArgs e)
		{
			AddSortField(false);
		}

		private void btnToggleSortOrder_Click(object sender, System.EventArgs e)
		{
			ToggleSortOrder(listSortFields);
		}

		private void btnDelSort_Click(object sender, System.EventArgs e)
		{
			this.ListBoxDelField(this.listSortFields);
		}

		private void listSortFields_DoubleClick(object sender, System.EventArgs e)
		{
			ListBox lb = (ListBox)sender;
			ToggleSortOrder(lb);
		}

		// force order for explicit asc/desc
		private void ToggleSortOrder(ListBox lb, string forceOrder)
		{
			// no action if button pressed but none in the list
			if (lb.Items.Count == 0) return;
			// Get current
			int iSelectedIndex = lb.SelectedIndex;
			// assume 1st if 
			if (iSelectedIndex == -1) iSelectedIndex = 0;
			// swap order
			// check from 
			string s = lb.Items[iSelectedIndex].ToString();
			// detect not explicit prefix case and fix now to avoid more complicated logic later
			char prefix = s[0];
			if (prefix != '-' && prefix != '+')
				prefix = '+';			// infer  the prefix
			else
				s = s.Substring(1);		// .. or strip the prefix
			// here with prefix + or - and the undecorated field
			switch (forceOrder)
			{
				case "+": s = forceOrder + s; break;
				case "-": s = forceOrder + s; break;
				default:
					s = ((prefix == '+') ? "-" : "+") + s;
					break;
			}
			lb.Items[iSelectedIndex] = s;
		}
		private void ToggleSortOrder(ListBox lb)
		{
			ToggleSortOrder(lb, "");
		}

		private void label6_Click(object sender, System.EventArgs e)
		{

		}

		private void textDescription_TextChanged(object sender, System.EventArgs e)
		{

		}
		/* 
			Intention is to auto-fill the text filter. However when the code was disabled
			it was not working. I suspect this code dates from before the time of integer 
			selection fields. It was rarely used and never missed. Hence it is made obsolete
	
				private void btnAuto_Click(object sender, System.EventArgs e)
				{
					int iAutoFilterMax = 3;
					// clear content.
					this.listFilterFields.Items.Clear();
					// for each field in selected list
					ListBox lb = this.listViewFields;
					// hold selected 
					int iHold = lb.SelectedIndex;
					for (int idx = 0; idx < lb.Items.Count; ++idx)
					{
						// set selected
						this.listViewFields.SelectedIndex = idx;
						// add to filter list
						if (IsSelectedOneATextField())
							this.ListBoxAddField(this.listViewFields, listFilterFields);
						// count filter list
						if (listFilterFields.Items.Count >= iAutoFilterMax)
							// quit if three
							break;
					}
					lb.SelectedIndex = iHold;
				}
		*/
		private void btnAddNumSearch_Click(object sender, System.EventArgs e)
		{
			this.ListBoxAddFields(listViewFields, listNumsearchFields);
		}

		private void btnDelNumSearch_Click(object sender, System.EventArgs e)
		{
			this.ListBoxDelField(listNumsearchFields);
		}

		private void btnShowAll_Click(object sender, System.EventArgs e)
		{
			setMatchString("");
		}

		private void btnUpdate_Click(object sender, EventArgs e)
		{
			UpdateFieldList();
		}

		private void btnUp_Click(object sender, System.EventArgs e)
		{
			MoveUp();
		}

		private void btnDown_Click(object sender, System.EventArgs e)
		{
			MoveDown();
		}

		private void MoveUp()
		{
			// get selected of source
			int iSelectedIndex = this.listViewFields.SelectedIndex;
			// no action if none selected
			if (iSelectedIndex <= 0) //na or at the top
				return;
			string ColumnName = listViewFields.Items[iSelectedIndex].ToString();
			listViewFields.Items.RemoveAt(iSelectedIndex);
			--iSelectedIndex;
			listViewFields.Items.Insert(iSelectedIndex, ColumnName);
			this.listViewFields.SelectedIndex = iSelectedIndex;
		}

		private void MoveDown()
		{
			// get selected of source
			int iSelectedIndex = this.listViewFields.SelectedIndex;
			// no action if none selected
			if (iSelectedIndex == -1 || iSelectedIndex + 1 >= this.listViewFields.Items.Count) //na or at the bottom
				return;
			string ColumnName = listViewFields.Items[iSelectedIndex].ToString();
			listViewFields.Items.RemoveAt(iSelectedIndex);
			++iSelectedIndex;
			listViewFields.Items.Insert(iSelectedIndex, ColumnName);
			this.listViewFields.SelectedIndex = iSelectedIndex;
		}

		private void listFields_Leave(object sender, System.EventArgs e)
		{
			//            setMatchString("");
		}

		private void listFields_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
		{
			char c = e.KeyChar;
			if ((c >= '0' && c <= '9')
				|| (c >= 'A' && c <= 'Z')
				|| (c >= 'a' && c <= 'z')
				|| (c == '_' || c == '_'))
			{
				setMatchString(this.m_MatchString + c);
				e.Handled = true;
			}
			else if (c == 8)
			{
				int l = this.m_MatchString.Length;
				if (l > 0)
				{
					setMatchString(this.m_MatchString.Substring(0, l - 1));
					e.Handled = true;
				}
			}
			else if (c == 27)
			{
				setMatchString("");
				e.Handled = true;
			}
			else if (c == 32)
			{
				// 
				this.ListBoxAddFields(listFields, listViewFields);
				setMatchString("");
				e.Handled = true;
			}
		}

		private void listFields_KeyDown(object sender, KeyEventArgs e)
		{
			ListNavigator navigator = ((sender as ListBox).Tag as ListNavigator);
			if (navigator != null && navigator.HandleKey(e)) return;
		}

		private void listViewFields_KeyDown(object sender, KeyEventArgs e)
		{
			ListNavigator navigator = ((sender as ListBox).Tag as ListNavigator);
			if (navigator != null && navigator.HandleKey(e)) return;

			if (e.KeyCode == Keys.Delete)
			{
				if (e.Shift)
					this.DeleteViewFieldsFromSelected();
				else
					this.DeleteViewField();
				e.Handled = true;
			}
			else if (e.KeyCode == Keys.Space)
			{
				AddSortField(false);
				e.Handled = true;
			}
			else if (e.KeyCode == Keys.Add ||
					 (e.KeyCode == Keys.Down && e.Control))
			{
				MoveDown();
				e.Handled = true;
			}
			else if (e.KeyCode == Keys.Subtract ||
					 (e.KeyCode == Keys.Up && e.Control))
			{
				MoveUp();
				e.Handled = true;
			}
			else if (e.KeyCode == Keys.F && e.Control)
			{
				if (this.IsSelectedOneATextField())
				{
					// add to text
					this.ListBoxAddField(this.listViewFields, listFilterFields);
				}
				else if (this.IsSelectedOneANumberField())
				{
					this.ListBoxAddFields(listViewFields, listNumsearchFields);
				}
				e.Handled = true;
			}
		}

		private void listSortFields_KeyDown(object sender, KeyEventArgs e)
		{
			ListNavigator navigator = ((sender as ListBox).Tag as ListNavigator);
			if (navigator != null && navigator.HandleKey(e)) return;

			if (e.KeyCode == Keys.Delete)
			{
				this.ListBoxDelField(this.listSortFields);
				e.Handled = true;
			}
			// space to toggle sort order
			if (e.KeyCode == Keys.Space)
			{
				ToggleSortOrder(listSortFields);
				e.Handled = true;
			}
			else if (e.KeyCode == Keys.Add ||
					 (e.KeyCode == Keys.Up && e.Control))
			{
				ToggleSortOrder(listSortFields, "+");
				e.Handled = true;
			}
			else if (e.KeyCode == Keys.Subtract ||
					 (e.KeyCode == Keys.Down && e.Control))
			{
				ToggleSortOrder(listSortFields, "-");
				e.Handled = true;
			}
		}

		private void listFilterFields_KeyDown(object sender, KeyEventArgs e)
		{
			ListNavigator navigator = ((sender as ListBox).Tag as ListNavigator);
			if (navigator != null && navigator.HandleKey(e)) return;

			ListBox lb = sender as ListBox;
			// trap delete to remove
			if (e.KeyCode == Keys.Delete)
			{
				this.ListBoxDelField(lb);
				e.Handled = true;
			}
		}

		private void btnAddToFilter_Click(object sender, EventArgs e)
		{
			// get selected of source
			int iSelectedIndex = this.listViewFields.SelectedIndex;
			// no action if none selected
			if (iSelectedIndex == -1)
				return;
			// get selected string
			string ColumnName = listViewFields.Items[iSelectedIndex].ToString();
			// 
			string filterText = this.textMoreSql.Text;
			if (filterText.Length > 0)
				filterText += " and ";
			filterText += string.Format("{0} is not null", ColumnName);
			this.textMoreSql.Text = filterText;
			// set focus to the filter field for editing
			this.textMoreSql.Select(this.textMoreSql.Text.Length,0);
			this.textMoreSql.Focus();
		}
		
		private void btnLookup_Click(object sender, EventArgs e)
		{
			// must be a field selected for this to work
			string selectedField = this.GetSelectedOne();
			if (string.IsNullOrEmpty(selectedField))
				return;

			string driverName = this.m_Model.DataSource.DriverName;
			string connectionName = this.m_Model.CurrentConnection;
			string table = this.m_ViewDef.TableName;
			DbView.Resources.LookupInfo.Key key = new DbView.Resources.LookupInfo.Key(driverName, connectionName, table, selectedField);
			// find the existing commad if any
			DbView.Resources.LookupInfo.Data data = DbView.Resources.LookupInfo.Instance.FindData(key);
			LookupModel rec = LookupModel.DataTransfer(key, data);

			Object o = this.m_Model.DataSource.TryToGetOptionalInterface(DbViewDriver.OptionalInterface.Lookup);
			if (o != null)
			{
				DbViewDriver.ILookup iface = o as DbViewDriver.ILookup;
				// do it all
				LookupEditController controller = new DbView.LookupEditController(iface.GetSchemaInfo(), rec);
				LookupEditForm dlg = new DbView.LookupEditForm(controller);
				if (dlg.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)
				{
					DbView.Resources.LookupInfo.Data report = LookupModel.DataTransfer(rec, key);
					DbView.Resources.LookupInfo.Instance.AddLookup(key, report);
					DbView.Resources.LookupInfo.Instance.SaveConfig();
				}
			}
		}

		private void listViewFields_SelectedIndexChanged(object sender, EventArgs e)
		{
			/*
					  if (this.IsSelectedOneADateField())
					  {
						  this.comboDateFormat.Enabled = true;
						  // 
						  int iSelectedIndex = this.listViewFields.SelectedIndex;
						  string ColumnName = listViewFields.Items[iSelectedIndex].ToString();
						  int Format = this.m_DateFormatManager[ColumnName];
						  int seq = this.m_DateFormatManager[Format];
						  this.comboDateFormat.SelectedIndex = seq;
					  }
					  else
					  {
						  this.comboDateFormat.Enabled = false;
						  this.comboDateFormat.SelectedIndex = -1;
					  }                
		  */
		}

		private void chkHelpTips_CheckedChanged(object sender, EventArgs e)
		{
			SynchronizeToolTipState(sender as CheckBox);
		}

		private void SynchronizeToolTipState(CheckBox ch)
		{
			// assume the tooltip is tied to the check box that controls activation
			ToolTip tt = ch.Tag as ToolTip;
			// if it's a tooldtip sync active state to checkbox state.
			if (tt != null)
				tt.Active = ch.Checked;
		}

		private void UpdateFieldList()
		{
			Command getData = new Command(Commands.Cmnd.TableData);
			ViewContext vc = new ViewContext(getData);
			vc.ObjectName = this.m_ViewDef.TableName;
			DataTable dt = this.m_Model.DataSource.BuildTable(getData, vc);
			this.m_ViewDefUpdate = ViewDefinitionManager.makeNewViewDefinition(dt);
			// show the change
			this.m_MatchString = ""; // probably is already
			PopulateFields(this.m_MatchString); // force a redisplay

		}

		// property to encapsulate the preferred selection of the newly updated list 
		// to the origial list, but for source field display only
		private ViewDefinition FieldListDef
		{
			get
			{
				return (this.m_ViewDefUpdate != null) ? this.m_ViewDefUpdate : this.m_ViewDef;
			}
		}

		private ViewDefinition m_ViewDef;
		private ViewDefinition m_ViewDefUpdate; // hold new default view def if created.
		private Model m_Model;
		private String m_OriginalName; 
		/*
				private DataTable this.m_dt;
				private ArrayList this.m_TableList;
				private ArrayList this.m_AliasList;
				private ArrayList this.m_TableFieldList;
		*/
		private int m_NewViewMaxColumnCount = 10; // default 10 columns 
		private string m_MatchString = "";
		private DragDropManager m_DragManager;

		private string HELP_STRING = @"
textViewName
The DataView name. This is either the name of the table
on which the view is based or a name that you enter. If
you enter a new name then the DataView will be saved and 
appear in the drop-down list on the main screen.
If you leave the name the same as the table name then 
this DataView will not be saved after the application is 
closed.
%%%
textDescription
The table on which the DataView is based.
%%%
chkPermanent
If this box is unchecked then the DataView configuration
will be discarded when the application is closed. Check 
the box to save it for later use.
%%%
listFields
Available fields for selection into the grid. Double-click,
or drag and drop a field into the list to the right of this.
Use the [>] button to select multiple fields. 

When the list has focus typing letters will filter the fields.
To restore the full list press the [Reset list] button or the 
[Esc] key.
%%%
listViewFields
Lists the fields that will be displayed in the DataView in the
column order that they will appear. Select from the Fields list 
on the left and double-click or drag and drop them into this list.

Remove fields either by dragging them out of the list or pressing
[<] on the left. Reorder fields with the [Up] and [Dn] buttons or
by dragging them up and down in the list.

DataView fields can be added to the lists on the right of this to
select them for sorting or to be filter fields.
%%%
btnShowAll
When this field list above is filtered (the items listed are in red) 
press the [Reset list] button or the [Esc] key to restore the list.
%%%
textMoreSql
Use this to enter a SQL clause to restict the rows displayed
by this DataView. Be sure to use correct SQL syntax or it 
will generate an error. Eg. remember to put single-quotes 
around literal strings. Press the [add To Filter] button to
add the selected DataView field to this clause.
%%%
btnAddToFilter
Press this to add the selected DataView field to the Additional
filter expression below. 
%%%
listSortFields
Lists the fields used to sort the DataView. Use the [>] button
to add a field in ascending sort order. Alternatively drag and
drop fields from the DataView fields list to the left. You can 
change the sort order to descending by double-clicking on the 
sort field or pressing the [~] button. Press [<] to remove fields 
from the list.
%%%
listFilterFields
Lists the fields to search when text is entered into the filter 
box on the main screen. Use the [>] button to add a field selected
from the DataView fields and [<] to remove fields from the filter
list. Note: only character fields can be added to this list. 
Numeric search fields should be added to the Number Search list
below.
%%%
listNumsearchFields
Lists the fields to search when a number is entered into the filter 
box on the main screen. Use the [>] button to add a field selected
from the DataView fields and [<] to remove fields from the filter
list. Note: only numeric fields can be added to this list. 
Character-based search fields should be added to the Text Filter list
above.
%%%
btnAddField
Adds all the fields selected in the list on the left to the 
DataView list on the right.
%%%
btnDelField
Removes all the fields selected in the DataView list on the right.
%%%
btnDelFields
Removes from the DataView list all of the fields below the selected
field. Does not remove the selected field. This is most useful for
modifying the DataViews automatically created when you double-click
on a table with a large number of fields.
%%%
btnUp
Moves the currently selected DataView field up in the list. If
more than one field is selected only the top field moves.
%%%
btnDown
Moves the currently selected DataView field down the list. If
more than one field is selected only the top field moves.
%%%
btnAddSortAsc
Press this button to add the currently selected DataView field 
to the sort field list as an ascending sort key. If more than
one field is selected only the top field is added.
%%%
btnToggleSortOrder
Press this button to change the sort order of the selected 
sort field. When the field name is prefixed with - then the
sort order is descending. Otherwise it is ascending.
%%%
btnDelSort
Press this button to remove the currently selected sort field
from the list.
%%%
btnAddFilter
Press this button to add the currently selected DataView field 
to the Text Filter list. Note: only character fields can be 
added to this list. Numeric search fields should be added to 
the Number Search list below.
%%%
btnDelFilter
Press this button to remove the currently selected Text Filter
field from the list.
%%%
btnAddNumSearch
Press this button to add the currently selected DataView field 
to the Number Search list. Note: only numeric fields can be added
to this list. Character-based search fields should be added to 
the Text Filter list above.
%%%
btnDelNumSearch
Press this button to remove the currently selected Number Search
field from the list.
%%%
btnUpdate
Press this button to update the field list from the database.
You will need to do this when a field has been added to the table
which does not appear in the list.
%%%
btnClone
Press this button to create a copy of the current view that you
can modify while keeping the original view intact. You may only
clone from permanent views.
";




	}

	// Handle Ctrl -> and Ctrl <- for list navigation.
	class ListNavigator
	{
		internal ListNavigator(ListBox lb, ListBox lbPrev, ListBox lbNext)
		{
			this.m_This = lb; ;
			this.m_Prev = lbPrev;
			this.m_Next = lbNext;
			this.m_This.GotFocus += new EventHandler(this.GetFocusHandler);
			//			this.m_This.LostFocus += new EventHandler(LoseFocusHandler);
		}

		internal bool HandleKey(KeyEventArgs e)
		{
			// Choice Left/Right arrow or strictly COntrol + Left/Right
			//			if (e.Control && e.KeyCode == Keys.Right)
			if (e.KeyCode == Keys.Right)
			{
				this.m_LastSelected = this.m_This.SelectedIndex;
				this.m_This.SelectedIndex = -1;
				//this.m_Next.Focus();
				this.FocusToNext(this.m_This);
				e.Handled = true;
			}
			else if (e.KeyCode == Keys.Left)
			//			else if (e.Control && e.KeyCode == Keys.Left)
			{
				this.m_LastSelected = this.m_This.SelectedIndex;
				this.m_This.SelectedIndex = -1;
				this.FocusToPrevious(this.m_This);
				//this.m_Prev.Focus();
				e.Handled = true;
			}
			return e.Handled;
		}

		internal void FocusToNext(ListBox sender)
		{
			if (this.m_Next.Items.Count > 0 || this.m_Next == sender) // this.m_Next == sender means its looped right around
				this.m_Next.Focus();
			else
			{
				ListNavigator nextNavigator = (this.m_Next.Tag as ListNavigator);
				if (nextNavigator != null)
					nextNavigator.FocusToNext(sender);
			}
		}

		internal void FocusToPrevious(ListBox sender)
		{
			if (this.m_Prev.Items.Count > 0 || this.m_Prev == sender) // this.m_Next == sender means its looped right around
				this.m_Prev.Focus();
			else
			{
				ListNavigator nextNavigator = (this.m_Prev.Tag as ListNavigator);
				if (nextNavigator != null)
					nextNavigator.FocusToPrevious(sender);
			}
		}

		private void GetFocusHandler(object sender, EventArgs e)
		{
			if (this.m_This.SelectedIndex == -1)
				this.m_This.SelectedIndex = (this.m_LastSelected > -1) ? this.m_LastSelected :
										(this.m_This.Items.Count > 0) ? 0 : -1;

		}

		private void LoseFocusHandler(object sender, EventArgs e)
		{
			this.m_LastSelected = this.m_This.SelectedIndex;
			this.m_This.SelectedIndex = -1;
		}

		int m_LastSelected = -1;
		ListBox m_This;
		ListBox m_Prev;
		ListBox m_Next;
	}
}
